# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: inkyu

import logging
from collections import namedtuple
from enum import IntEnum

from dateutil import parser

from coin.exchange.base.order_gateway import OrderSide, OrderType
from coin.exchange.upbit_v1.kr_rest.product import UpbitProduct


class UpbitExchangeOrderState(IntEnum):
  WAIT = 1
  DONE = 2
  CANCEL = 3

  @staticmethod
  def from_str(status):
    if status == 'wait':
      return UpbitExchangeOrderState.WAIT
    elif status == 'done':
      return UpbitExchangeOrderState.DONE
    elif status == 'cancel':
      return UpbitExchangeOrderState.CANCEL
    else:
      return ValueError(status)

  def to_str(self):
    if self == UpbitExchangeOrderState.WAIT:
      return 'wait'
    elif self == UpbitExchangeOrderState.DONE:
      return 'done'
    elif self == UpbitExchangeOrderState.CANCEL:
      return 'cancel'
    else:
      return ValueError(self)


UpbitOrderSnapshot = namedtuple('UpbitOrderSnapshot',
                                [
                                    'timestamp_created',
                                    'exchange_order_id',
                                    'order_side',
                                    'order_type',
                                    'price_orig',
                                    'state',
                                    'native_symbol',
                                    'qty_orig',
                                    'qty_filled',
                                    'paid_fee',
                                    'trades_count'
                                ])


def _parse_order_side(order_side):
  if order_side == 'bid':
    return OrderSide.BUY
  elif order_side == 'ask':
    return OrderSide.SELL
  else:
    raise ValueError(order_side)


def _parse_order_type(order_type):
  if order_type == 'limit':
    return OrderType.LIMIT
  elif order_type == 'market':
    return OrderType.MARKET
  else:
    raise ValueError('unknown order type %s' % order_type)


class UpbitPrivateParser(object):
  @staticmethod
  def parse_order(message):
    exchange_order_id = message['uuid']
    order_side = _parse_order_side(message['side'])
    order_type = _parse_order_type(message['ord_type'])
    price_orig = float(message.get('price') or 0)
    qty_orig = float(message['volume'])
    qty_filled = float(message['executed_volume'])
    paid_fee = float(message['paid_fee'])
    trades_count = int(message['trades_count'])
    timestamp_created = int(parser.parse(message['created_at']).timestamp() * 1e9)
    state = UpbitExchangeOrderState.from_str(message['state'])

    # Remaining entries:
    # [reserved_fee, remaining_fee, locked, remaining_volume]
    return UpbitOrderSnapshot(timestamp_created=timestamp_created,
                              exchange_order_id=exchange_order_id,
                              order_side=order_side,
                              order_type=order_type,
                              price_orig=price_orig,
                              state=state,
                              native_symbol=message['market'],
                              qty_orig=qty_orig,
                              qty_filled=qty_filled,
                              paid_fee=paid_fee,
                              trades_count=trades_count)

  @staticmethod
  def parse_orders(message):
    assert isinstance(message, list), message
    order_snapshots = []
    for order_data in message:
      order_snapshot = UpbitPrivateParser.parse_order(order_data)
      if order_snapshot.order_type == OrderType.LIMIT:
        order_snapshots.append(order_snapshot)
      elif order_snapshot.order_type == OrderType.MARKET:
        logging.error('Weird! Market order received! %s', order_data)
      else:
        logging.error('Unknown upbit order type %s', order_data)
    return order_snapshots
